package com.versiFramework.services{
    import com.versiFramework.core.IService;
    import com.versiFramework.core.ctrlEvent;
    import com.versiFramework.events.serviceEvent;
    import com.versiFramework.events.versiEvent;
    import com.versiFramework.versi;
    
    import flash.events.EventDispatcher;
    import flash.utils.ByteArray;
    
    import mx.collections.ArrayCollection;
    import mx.rpc.AbstractOperation;
    import mx.rpc.AsyncToken;
    import mx.rpc.Responder;
    import mx.rpc.events.FaultEvent;
    import mx.rpc.events.ResultEvent;
    import mx.rpc.remoting.mxml.RemoteObject;
			
	public class ROService extends EventDispatcher implements IService {
		private var _remoteservice : mx.rpc.remoting.mxml.RemoteObject;
		
		//var newEndpoint:String = 'http://' + newServer.SERVER + '/' + newServer.GATEWAY + '/';	
		
		private var _endpoint:String="/flex2gateway";
		private var _source:String;
		private var _destination:String="ColdFusion";
		private var _name:String;
		
		//* Properties *//
		public function get name():String
		{
			return _name;
		}
		public function set name(setVal:String):void
		{
			_name=setVal;
		}
				
		public function set endpoint(endpoint:String):void {
            _endpoint = endpoint;
        }

        public function get endpoint():String {
            return _endpoint;
        }
		
		public function set destination(destination:String):void {
			_destination = destination;
		}
		
		public function get destination():String {
			return _destination;
		}
		
		public function set source(source:String):void {
			_source = source;
			if (!name)
			{
				name=source.split('.').pop();
			}
		}
		
		public function get source():String {
			return _source;
		}
		
		//* Constructor *//
 		public function ROService(source:String=null,name:String=null,endpoint:String=null)
 		{
			if (endpoint) this.endpoint = endpoint;
			if (name) this.name = name;
			if (source) this.source = source
			super();
		}

		//* Remote object instance *//	
		protected function get remoteservice() : mx.rpc.remoting.mxml.RemoteObject
		{
			if (! _remoteservice )
			{
				_remoteservice= new mx.rpc.remoting.mxml.RemoteObject();
				_remoteservice.source = source;
			}
			_remoteservice.destination = destination;
			_remoteservice.endpoint=endpoint;
			return _remoteservice;
		}
		
		//*	operation *//
		public function send(method:String,args:Object=null,showbusy:Boolean=true,returnFunc:Function=null,faultFunc:Function=null,tokenProperty:*=null):void
		{
			if(returnFunc==null)
			{
				returnFunc = onResult;
			}	
			if(faultFunc==null)
			{
				faultFunc = serverFault;
			}
			
			if(!endpoint || !endpoint.length || !source || !source.length)
			{
				var fault:FaultEvent = new FaultEvent(FaultEvent.FAULT);
				serverFault(fault);
				return;
			}
			
			var token:AsyncToken;
			
			remoteservice.showBusyCursor=showbusy;
			
			var op:mx.rpc.AbstractOperation = remoteservice.getOperation(method);
            if (args)
            {
				
				token = op.send(args);
            }
            else
            {
				//token = remoteservice.getOperation(method).send();
				token = op.send();
            }
            token.addResponder(new mx.rpc.Responder(returnFunc,faultFunc));
			if (tokenProperty)
			{
				token.tokenProperty = tokenProperty;
			}            
		}
				
		//*	default responder Events *//
		//The following methods should be depreciated in favor of passing in specific result & fault handlers
		
		protected function onResult(event:ResultEvent):void
		{ 	
			var newresult:Object=event.result as Object;
				var op:Object=event.token.message;
				var tokenProperty:*;
				
				if (event.token.hasOwnProperty("tokenProperty"))
				{
					tokenProperty = event.token.tokenProperty;
				}
				
				if (op.body.length && op.body[0].hasOwnProperty("returnType")) //this is depreciated in favor of asyncToken properties
				{
					this.dispatchEvent( new serviceEvent(op.body[0].returnType, newresult, tokenProperty) );
				}
				else if (this.hasOwnProperty(op.operation + serviceEvent.RESULT))
				{
					this[op.operation + serviceEvent.RESULT](event);
				}
				else
				{
					this.dispatchEvent( new serviceEvent(op.operation, newresult, tokenProperty) );
				}
		}
		
		//* default	fault Event handler *//
		protected function serverFault(event:FaultEvent):void
		{	
			if (! event.token || ! event.token.message)
			{
				doServiceFault(event); return;
			}
			else
			{
				var op:Object=event.token.message;
				var tokenProperty:*;
				if (event.token.hasOwnProperty("tokenProperty"))
				{
					tokenProperty = event.token.tokenProperty;
				}
				
				if (op.body.length && op.body[0].hasOwnProperty("returnType"))
				{
					this.dispatchEvent( new serviceEvent(op.body[0].returnType + serviceEvent.FAULT, event,tokenProperty) );
				}
				else if (this.hasOwnProperty(op.operation + serviceEvent.FAULT)) 
				{
					this[op.operation + serviceEvent.FAULT](event);
				}
				else
				{	
					doServiceFault(event.message);
				}
			}
		}
		
		//* utility functions in support of the default handlers *//
		public function doEvent(type:String,data:*,target:String="all"):void
		{
			versi.doEvent(type,data,target)
		}
		public function doServiceFault(msg:*):void
		{
			this.dispatchEvent( new serviceEvent(serviceEvent.FAULT,msg) ); 
		}	
		public function clone(source:Object):*
		{
		    var myBA:ByteArray = new ByteArray();
		    myBA.writeObject(source);
		    myBA.position = 0;
		    return(myBA.readObject());
		}

	}

}